#ifndef RENDERABLE_H_
#define RENDERABLE_H_

#include "RayTraceable.h"
#include "Material.h"
#include "BBox.h"


#ifdef DEBUGGING
#include <string>
#endif
/************************************************************************/
/*  Uniforms the way we render objects                                  */
/************************************************************************/

class Renderable : public RayTraceable
{
public:
    //default
    Renderable() : m_hasValidBox(false),m_reflective(false), m_castsShadows(true), m_recievesShadows(true), 
        m_reflectance(0.0f),m_transparent(false), m_opacity(1.0f),m_textured(false){}
    //material, reflective
    Renderable(const Material& m, bool ref, float reflectance) : 
        m_hasValidBox(false),m_reflective(ref), 
        m_material(m),m_reflectance(reflectance),
        m_castsShadows(true), m_recievesShadows(true),
        m_transparent(false), m_opacity(1.0f),m_textured(false){}
    //material, reflective, transparent
    Renderable(const Material& m, bool ref, float reflectance, bool trans, float opacity) : 
        m_hasValidBox(false),m_reflective(ref), m_material(m),
        m_reflectance(reflectance),m_castsShadows(true), m_recievesShadows(true),
        m_transparent(trans), m_opacity(opacity),m_textured(false){}

    /* Virtual Dtr */
    virtual ~Renderable() = 0 {}

    /* Simple implementation that can be removed */
    void SetColor(float r, float g, float b){m_color.SetAll(r,g,b);}
    void SetColor(const Color& color){m_color = color;}
    Color GetColor(){return m_color;}

    const Material& GetMaterial(){return m_material;}
    void SetMaterial(const Material& m){m_material = m;}
    bool UseSpec(){return m_material.GetSpecular().m_a != 0;}
    bool Reflect(){return m_reflective;}
    float GetReflectance() const {return m_reflectance;}
    void SetReflectance(float ref) {m_reflectance = ref;}
    bool IsTransparent(){return m_transparent;}
    float GetRefractiveIndex(){return 1.122f;} // HACK HACK HACK
    float GetOpacity(){return m_opacity;}
    bool IsTextured(){return m_textured;}
    const BBox& GetBox(){return m_box;}
    bool HasBox(){return m_hasValidBox;}
    virtual void CalculateBox() = 0;
    bool CastsShadows(){return m_castsShadows;}
    bool RecievesShadows(){return m_recievesShadows;}
    void MakeLight(){m_castsShadows = false; m_recievesShadows = false;}

    /* Special debug build only information string */
#ifdef DEBUGGING
    std::string m_information;
    //Amazing implementation.
    virtual bool Hit_Debug(const Ray& ray, float& tmin, ContactData& data) const
    {
        return Hit(ray,tmin,data);
    }
#endif

protected:
    Color m_color;
    Material m_material;
    //2 is highly reflective, 0 is none
    float m_reflectance;
    //saves checking reflectance for 0!
    bool m_reflective;
    //Only triangles have this functionality
    bool m_textured;
    //
    bool m_transparent;
    float m_opacity;

    //To do : implement this
    bool m_castsShadows;
    bool m_recievesShadows;

    //Possible design flaw.
    BBox m_box;
    bool m_hasValidBox;
};

#endif